home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_200
/
297_01
/
prmanual.txt
< prev
next >
Wrap
Text File
|
1991-12-30
|
20KB
|
579 lines
Feb 17 1989
Revised July 22 1989
Revised December 25 1991
Revised January 1 1992
Small Prolog User Guide & Reference
Introduction.
-------------
Small Prolog is a public domain implementation of the Prolog Language, with
C source provided.
You can do what you like with the code, save claim it as your own work.
If you embed this into a commercial application I would nevertheless
appreciate a free copy of your software.
There are other public domain implementations around, but I dont know of
one where you get the C code apart a public domain compiler called
Stony Brook Prolog, but it hasnt yet been ported to the PC.
The design goals were:
A minimal usable implementation.
Maximum portability.
Educational code.
Extensibility.
A small object code.
Embeddability.
Facilitate meta-programming.
Of course these goals have not been fully met!
It helps to read Hogger's book "An introduction to logic programming"
(Academic Press 1984)
to understand the code. You could also try
Maier & Warren's "Computing with logic" - Benjamin Cummings Ed.
1988 as an alternative.
On the negative side:
The syntax is LISP-like which has its advantages for meta-programming
and small code, but I find that it is not very friendly.
There is no garbage collection of any sort. It's surprising how far
you can get away with this. If you want to garbage collect on the
heap, then I suggest that you make a separate zone for pairs and
modify get_node() so that it in fact allocates a pair but only
returns the head. Then adapt the garbage collector of the source code
of Xlisp (which is public domain).
You could also garbage collect some of the substitution stack. The
only easily available literature I know of is an article by Maurice
Bruynehooge in "Implementations of Prolog" edited by John Campbell,
published by John Wiley. The book is full of typos, so good luck.
There are quite a few improvements to the code to be made (at this time)
such as last call optimisation.
The trace facilities of version 2 are no longer minimal.
Not all the "standard" builtins have been included.
We thought you would enjoy putting these in.
Syntax
------
The syntax of the prolog is extremely simple. You can look
at one of the prolog source files (*.spr) provided to get an idea
or you can look at the C souce code, or you can read the following:
Comments are as in the C language:
/* This is a comment
*/
The program may be layed out with as many spaces, line_feeds and
tabs as you like providing you don't chop a lexical item in two.
A lexical item is an identifier or a number or a string or
brackets or the vertical bar.
Although strictly speaking a program is a set of clauses
AND a query, we shall call a set of clauses a program.
The following is a context free grammar for the syntax.
Nonterminals are distinguished from terminals by putting them
inside angle brackets. Comments follow the rewrite rules and are
inside /* */.
<program> -> <empty>
<program> -> <clause> <program>
<clause> -> <rule>
<clause> -> <fact>
<rule> -> (<head> <goals>)
<fact> -> (<head>)
<fact> -> <head> /* alternative */
<head> -> (<clause predicate> <arguments>)
<head> -> (<clause predicate> <arguments>|<argument>)
/* use the second kind of head with caution */
<clause predicate> -> <atom other than builtin>
<arguments> -> <empty>
<arguments> -> <argument><arguments>
<argument> -> <atom>
<argument> -> <list>
<argument> -> <integer>
<argument> -> <real> /* depends on conditional compilation */
<argument> -> <string>
<argument> -> <variable>
<argument> -> <char> /* depends on conditional compilation */
<atom> -> ()
/* you can space the brackets out */
<atom> -> <small letter><identifier tail>
<variable> -> _
<variable> -> _<identifier tail>
<variable> -> <capital_letter><identifier tail>
<identifier tail> -> <empty>
<identifier tail> -> <character other than space,bracket,quote or bar>
<identifier tail> -> <identifier tail><identifier tail>
<list> -> (<arguments>)
<list> -> (<arguments>|<argument>)
<integer> -> <sign><unsigned integer>
<integer> -> <unsigned integer>
<unsigned integer> -> <digit>
<unsigned integer> -> <digit><unsigned integer>
<sign> -> -
<sign> -> <empty>
<goals> -> <goal>
<goals> -> <goal><space><goals>
<goal> -> (<predicate><space><arguments>)
<goal> -> (<predicate><space><arguments>|<argument>)
/* dont use this form if the predicate is builtin */
<predicate> -> <small letter><identifier tail>
<real>-><integer>.<unsigned integer>
<string> -> <string quote> <sequence of characters> <string quote>
/* Dont put a string quote in the sequence of characters unless it is
* immediately followed by another string quote -only one is considered.
*
*/
<char> -> '<printable character>'
<char> -> '\n'
<char> -> '\r'
<char> -> '\t'
<char> -> '\v'
<char> -> '\f'
<char> -> '\''
<char> -> '\"'
<char> -> '\<octal digit>'
<char> -> '\<octal digit><octal digit>'
<char> -> '\<octal digit><octal digit><octal digit>'
<query> -> (<goals>)
<query> -> <goal>
/* The last form is permitted for one goal-queries */
<string quote> -> "
/* END OF GRAMMAR */
Now for 4 sample queries. You don't type the "?-".
?-((writes "Hello, world")(nl))
?-((nl))
?-(space_left Heap Strings Dyn SUb Trail Temp)
?-((writes "What is your name?")(read X)
(writes "Hello, ")(display X))
?-(writes "This :"" is an embeded double quote")
Builtins:
---------
Builtins are predefined predicates that in fact call on C code.
The builtins are documented in the source file prbltin.c.
The file help.spr provides "on line" documentation.
You could add more builtins by imitating that file, but
we suggest using an extra file.
You should try to be consistent with Clocksin and Mellish's
builtins (see bibliography). Of course it's not as interesting
trying to define predicates like "functor", "arg" and "univ".
To add your own builtins you should know the following:
Small Prolog uses many global variables defined in prlush.c
"Arguments" is the list of arguments of the current goal and "SubstGoal"
is the (substitution) environment for this. To get at the different
elements of "Arguments" you can use the ARG_XXX macros in prbltin.h.
All functions make frequent use of the dereference() function in
prunify.c so it is important to understand this as soon as you have
understood the basic data types. This function dereferences a
term in an environment and updates the globals DerefNode and
DerefSubst which represent the resulting derefenced object.
They are globals.
The following scheme gives you an idea of how a builtin might be
built.
Pmybuiltin()
{
/* local variables used below */
int result;
integer i;
char *s;...
/* argument extaction macros */
ARG_INT(1,i) /* the first arg expected is an INT, i is set to this */
ARG_STRING(2,s); /* the second arg expected is a string */
...
result = my_function(i,s,...,&o,...);/* you define this */
bind_...(3,o); /* the third argument is bound to "o" */
if(result == MY_SUCCESS/* you define this */)return 1;
if(result == MY_FAIL/* ditto */)return 0;
else
return(CRASH);/* force a stack dump */
}
Calling a builtin with extra arguments is harmless - they are
just ignored. Missing arguments or arguments of a wrong type
generally force a "stack dump" so you know where the program
was when it crashed. This is a print out of all pending goal lists
of the ancestors of the current goal.
The top-most goal list is the list of goals of the current clause.
Underneath this are the goals of the clause that called that etc.
From version 2 on a builtin may backtrack by making the related
function return ND_SUCCESS. The repeat builtin does this.
It is the builtin's responsability to update ND_builtin_next_nodeptr
when it is called. That value is restored on backtracking and
is the only information that is saved from one call to the next.
See how the gennum predicate is implemented.
Input-output:
-------------
The i